Skip to main content

Asynchronous Functions

warning

This chapter is in development

info

See the reference section on Async

Asynchronous programming is a technique that enables your program to start a potentially long-running task (or a request from a user) and still be able to be responsive to other events while that task runs, rather than having to wait until that task has finished. Once that task has finished, your program is presented with the result.

This is a relatively new concept inherited from other modern languages. It allows to write asynchronous sequential code avoiding callback hell. AsyncFunction and Await expressions and their concepts are built on top of Promises framework.

Limitations

The following constructions are supported with Await:

  • Set
  • CompoundExpression
  • If
  • Module, With
  • _Symbol or any other singular expressions

What is not supported (by now)

  • Loops: While, For, Do
  • Tables and maps: Map, Table

Side by side comparison

Here is the same code-block using promises and AsyncFunction

Using promises
temperature = "Loading";
TextView[temperature // Offload]

Then[ParallelSubmitAsync[URLRead["https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m"]], Function[response,
temperature = ImportByteArray[response["BodyByteArray"], "RawJSON"]["current", "temperature_2m"];
]]
Using AsyncFunction
temperature = "";
TextView[temperature // Offload]

AsyncFunction[Null, Module[{response},
temperature = "Loading";
response = ParallelSubmitAsync[URLRead["https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m"]] // Await;
temperature = ImportByteArray[response["BodyByteArray"], "RawJSON"]["current", "temperature_2m"];
]][]

The things are getting much more readable if you have multiple nested Then and promises.

Naturally async functions

There are many built-in functions, which by the default return Promise

Examples

danger

Be aware of the evaluation context loss after each Await statement. Provide EvaluationNotebook, EvaluationCell or CurrentWindow if necessary.

Heavy branching

In this example we demonstrate branching, assignments and compound expressions in asynchronous functions:

p1 = Promise[];
p2 = Promise[];
p3 = Promise[];

win = CurrentWindow[];

f = AsyncFunction[Null, With[{},
Speak["Press p1", "Window"->win];
p1 // Await;
Speak["Press p2A or p2B", "Window"->win];
Module[{m = -100},
m = Await[p2];
Speak["Pause 2 seconds", "Window"->win];
PauseAsync[2] // Await;

If[m > 4,
Speak["Press p3", "Window"->win];
m = Await[p3];
];

StringTemplate["Result: ``"][m]
]
]];

Then[f[], Speak];

To simulate async events here we use buttons

Button["p1", EventFire[p1, Resolve, True]]
Button["p2A", EventFire[p2, Resolve, 1]]
Button["p2B", EventFire[p2, Resolve, 5]]
Button["p3", EventFire[p3, Resolve, 10]]